#include <iostream>
#include <unistd.h>
#include <vector>
#include <string>
#include <pthread.h>
#include <cstring>
#include "Mutex.hpp"

#define NUM 5
using namespace std;

// 定义全局的锁会自动初始化和释放
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

int ticket = 1000;

class Thread
{
public:
    Thread(int number)
    {
        _name = "Thread-" + to_string(number);
        /*_lock = nullptr*/;
    }

public:
    string _name;
    /*pthread_mutex_t* _lock;*/
};

void *GrabTickets(void *args)
{
    Thread *t = static_cast<Thread *>(args);

    const char *name = t->_name.c_str();

    while (true)
    {
        {
            // 1.申请锁资源,申请成功则继续执行，申请失败会阻塞等待
            // pthread_mutex_lock(&lock);
            LockGuard lockguard(&lock); //RAII思想利用对象的生命周期以及自动调用构造和析构进行加锁和解锁

            if (ticket > 0)
            {
                usleep(1000);
                printf("who=%s, remain tickets:%d\n", name, ticket);
                ticket--;

                // pthread_mutex_unlock(&lock);
            }
            else
            {
                // 2.解锁
                // pthread_mutex_unlock(&lock);
                break;
            }
        }

        // 用来模拟后续操作，如果没有这个一开始申请到锁的线程会一直占用锁资源导致其他线程的饥饿问题
        usleep(13);
    }

    printf("%s...quit\n", name);

    return nullptr;
}

int main()
{
    vector<pthread_t> tids;
    vector<Thread *> ts;

    for (int i = 1; i <= NUM; i++)
    {
        Thread *t = new Thread(i);
        ts.push_back(t);

        pthread_t tid;
        pthread_create(&tid, nullptr, GrabTickets, t);
        tids.push_back(tid);
    }

    usleep(10000);

    for (int i = 0; i < tids.size(); i++)
    {
        pthread_join(tids[i], nullptr);
    }

    for (int i = 0; i < ts.size(); i++)
    {
        delete ts[i];
        ts[i] = nullptr;
    }

    return 0;
}